﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GameFramework.Data;
using GameFramework.DataTable;
using UnityGameFramework.Runtime;
using GameFramework;

namespace TowerDefence_Zombie.Data
{
    public sealed class DataTower : DataBase
    {
        private IDataTable<DRTower> dtTower;
        private IDataTable<DRTowerLevel> dtTowerLevel;
        private IDataTable<DRTowerStar> dtTowerStar;
        private IDataTable<DRTowerBuilder> dtTowerBuilder;

        public Dictionary<int, TowerData> dicTowerData;
        public Dictionary<int, TowerLevelData> dicTowerLevelData;
        public Dictionary<int, TowerStarData> dicTowerStarData;
        public Dictionary<int, Tower> dicTower;

        private List<TowerBuilderData> arrayTowerBuildData;

        private int serialId = 0;

        protected override void OnInit()
        {

        }

        protected override void OnPreload()
        {
            LoadDataTable("Tower");
            LoadDataTable("TowerLevel");
            LoadDataTable("TowerStar");
            LoadDataTable("TowerBuilder");
        }

        protected override void OnLoad()
        {
            dtTower = GameEntry.DataTable.GetDataTable<DRTower>();
            if (dtTower == null)
                throw new System.Exception("Can not get data table Tower");

            dtTowerLevel = GameEntry.DataTable.GetDataTable<DRTowerLevel>();
            if (dtTowerLevel == null)
                throw new System.Exception("Can not get data table TowerLevel");

            dtTowerStar = GameEntry.DataTable.GetDataTable<DRTowerStar>();
            if (dtTowerStar == null)
                throw new System.Exception("Can not get data table TowerStar");

            dtTowerBuilder = GameEntry.DataTable.GetDataTable<DRTowerBuilder>();
            if (dtTowerBuilder == null)
                throw new System.Exception("Can not get data table TowerBuilder");

            dicTowerData = new Dictionary<int, TowerData>();
            dicTowerLevelData = new Dictionary<int, TowerLevelData>();
            dicTowerStarData = new Dictionary<int, TowerStarData>();
            dicTower = new Dictionary<int, Tower>();
            arrayTowerBuildData = new List<TowerBuilderData>();

            DRTowerLevel[] drTowerLevels = dtTowerLevel.GetAllDataRows();
            foreach (var drTowerLevel in drTowerLevels)
            {
                if (dicTowerLevelData.ContainsKey(drTowerLevel.Id))
                {
                    throw new System.Exception(string.Format("Data tower level id '{0}' duplicate.", drTowerLevel.Id));
                }

                TowerLevelData towerLevelData = new TowerLevelData(drTowerLevel);
                dicTowerLevelData.Add(drTowerLevel.Id, towerLevelData);
            }

            DRTowerStar[] drTowerStars = dtTowerStar.GetAllDataRows();
            foreach (var drTowerStar in drTowerStars)
            {
                if (dicTowerStarData.ContainsKey(drTowerStar.Id))
                {
                    throw new System.Exception(string.Format("Data tower star id '{0}' duplicate.", drTowerStar.Id));
                }
                TowerStarData towerStarData = new TowerStarData(drTowerStar);
                dicTowerStarData.Add(drTowerStar.Id, towerStarData);
            }

            DRTower[] drTowers = dtTower.GetAllDataRows();
            foreach (var drTower in drTowers)
            {
                TowerLevelData[] towerLevelDatas = new TowerLevelData[drTower.Levels.Length];
                for (int i = 0; i < drTower.Levels.Length; i++)
                {
                    if (!dicTowerLevelData.ContainsKey(drTower.Levels[i]))
                    {
                        throw new System.Exception(string.Format("Can not find tower level id '{0}' in DataTable TowerLevel.", drTower.Levels[i]));
                    }
                    towerLevelDatas[i] = dicTowerLevelData[drTower.Levels[i]];
                }

                TowerStarData[] towerStarDatas = new TowerStarData[drTower.Stars.Length];
                for (int i = 0; i < drTower.Stars.Length; i++)
                {
                    if (!dicTowerStarData.ContainsKey(drTower.Stars[i]))
                    {
                        throw new System.Exception(string.Format("Can not find tower star id '{0}' in DataTable TowerStar.", drTower.Stars[i]));
                    }
                    towerStarDatas[i] = dicTowerStarData[drTower.Stars[i]];
                }

                TowerData towerData = new(drTower, towerLevelDatas, towerStarDatas);
                dicTowerData.Add(drTower.Id, towerData);
            }

            DRTowerBuilder[] drTowerBuilds = dtTowerBuilder.GetAllDataRows();
            for (int i = 0; i < drTowerBuilds.Length; i++)
            {
                arrayTowerBuildData.Add(new TowerBuilderData(drTowerBuilds[i]));
            }
        }

        #region 炮塔建造相关

        public bool CheckTowerBuildIsMaxLevel(int level)
        {
            return level >= arrayTowerBuildData.Count;
        }

        public bool GetTowerBuildData(int level, out TowerBuilderData data)
        {
            if (level < arrayTowerBuildData.Count)
            {
                data = arrayTowerBuildData[level - 1];
                return true;
            }
            data = null;
            return false;
        }

        #endregion

        private int GenrateSerialId()
        {
            return ++serialId;
        }

        public TowerData GetTowerData(int id)
        {
            if (!dicTowerData.ContainsKey(id))
            {
                Log.Error("Can not find tower data id '{0}'.", id);
                return null;
            }

            return dicTowerData[id];
        }

        public bool GetTowerData(int id, out TowerData towerData)
        {
            return dicTowerData.TryGetValue(id, out towerData);
        }

        public bool GetTowerStarData(int id, int star, out TowerStarData towerStarData)
        {
            if (GetTowerData(id, out var towerData))
            {
                towerStarData = towerData.GetStarData(star);
                return true;
            }
            towerStarData = null;
            return false;
        }

        public bool CheckTowerIsMaxLevel(int id, int towerLevel)
        {
            if (GetTowerData(id, out var towerData))
            {
                return towerLevel >= towerData.GetMaxLevel();
            }
            return false;
        }

        public Tower CreateTower(int towerId, int level = 0, bool isUpgrade = false)
        {
            if (!dicTowerData.ContainsKey(towerId))
            {
                Log.Error("Can not find tower data id '{0}'.", towerId);
                return null;
            }

            int serialId = GenrateSerialId();
            Tower tower = Tower.Create(dicTowerData[towerId], serialId, level, isUpgrade);
            dicTower.Add(serialId, tower);

            return tower;
        }

        public void DestroyTower(int serialId)
        {
            if (!dicTower.ContainsKey(serialId))
            {
                Log.Error("Can not find tower serialId '{0}'.", serialId);
                return;
            }

            ReferencePool.Release(dicTower[serialId]);
            dicTower.Remove(serialId);
        }

        public void DestroyTower(Tower tower)
        {
            DestroyTower(tower.SerialId);
        }

        protected override void OnUnload()
        {
            GameEntry.DataTable.DestroyDataTable<DRTower>();
            GameEntry.DataTable.DestroyDataTable<DRTowerLevel>();
            GameEntry.DataTable.DestroyDataTable<DRTowerBuilder>();

            dicTowerData = null;
            dicTowerLevelData = null;
            arrayTowerBuildData = null;

            if (dicTower != null)
            {
                foreach (var item in dicTower.Values)
                {
                    ReferencePool.Release(item);
                }
                dicTower.Clear();
            }

            serialId = 0;
        }

        protected override void OnShutdown()
        {
        }
    }
}